package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;

import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {

    /**定义socket监听的端口号*/
    private int port;

    private String webApps;


    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {

        // 加载解析相关的配置，web.xml
        loadServlet();

        // 定义一个线程池
        int corePoolSize = 10;
        int maximumPoolSize =50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("=====>>>Minicat start on port：" + port);
        /*
            多线程改造（使用线程池）
         */
        while(true) {

            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket,servletMap);
            //requestProcessor.start();
            threadPoolExecutor.execute(requestProcessor);
        }



    }


    private Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();

    /**
     * @description 加载webapps中的servlet
     * @author DingYiYuan
     * @time 2021/6/1 14:09
     */
    private void loadServlet() throws Exception {
        //加载容器初始参数
        loadParameter();
        File file = new File(webApps);
        File[] files = file.listFiles();
        if(files.length <= 0)
            return;
        for (File serverFile : files) {
            //读取XML
            String webXml = webApps + "/" + serverFile.getName() + "/src/main/resources/web.xml";
            FileInputStream fileInputStream = new FileInputStream(webXml);
            SAXReader saxReader = new SAXReader();
            saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            //自定义类加载器
            URLClassLoader urlClassLoader = getUrlClassLoader(serverFile);

            Element rootElement = saxReader.read(fileInputStream).getRootElement();
            List<Element> selectNodes = rootElement.selectNodes("//servlet");

            for (int i = 0; i < selectNodes.size(); i++) {
                Element element =  selectNodes.get(i);
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                //servlet对象
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();
                Object servlet = urlClassLoader.loadClass(servletClass).newInstance();
                //URL地址
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                servletMap.put(urlPattern, (HttpServlet) servlet);

            }
        }


    }

    //加载容器初始参数
    private void loadParameter() throws Exception {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();
        saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();

        //获取端口号
        Element portElement = (Element)rootElement.selectObject("//connecter");
        this.port = Integer.parseInt(portElement.attributeValue("port"));
        //获取程序基础路径
        Element hostElement = (Element)rootElement.selectObject("//host");
        this.webApps = hostElement.attributeValue("appBase");
    }

    //自定义类加载器"webapps/demo1/classes"
    private URLClassLoader getUrlClassLoader(File serverFile) throws MalformedURLException {
        String classpath = webApps + "/" + serverFile.getName() + "/classes";
        File file1 = new File(classpath);
        URL url = file1.toURI().toURL();
        return new URLClassLoader(new URL[]{url});
    }


    /**
     * Minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动Minicat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
